package com.lmc.form.script;

import com.free.bsf.core.base.BsfException;
import com.free.bsf.core.db.DbHelper;
import com.free.bsf.core.serialize.JsonSerializer;
import com.free.bsf.core.util.*;
import com.lmc.form.dao.dal.paas_form_model_dal;
import lombok.AllArgsConstructor;
import lombok.val;
import lombok.var;
import org.apache.commons.compress.compressors.gzip.GzipUtils;
import org.springframework.core.annotation.Order;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;

@Order(Integer.MAX_VALUE)
public class FormEventFilter implements Filter {
    JsonSerializer jsonSerializer = new JsonSerializer();

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        //文件上传不进行转发,识别表单数据,仅支持content-type
        if (req.getHeader("formKey") != null && req.getHeader("formAction") != null) {
            if (req.getHeader("Content-Type") != null && req.getHeader("Content-Type").toLowerCase().contains("json")) {
                try {
                    //根据表单key获取事件流
                    val formInfo = new formInfo(URLDecoder.decode(req.getHeader("formKey"), "utf-8"), URLDecoder.decode(req.getHeader("formAction"), "utf-8"));
                    try (RequestWrapper requestWrapper = new RequestWrapper(req)) {
                        val formInfoStr = jsonSerializer.serialize(formInfo);
                        var requestJson = (LinkedHashMap) jsonSerializer.deserialize(new String(requestWrapper.body), LinkedHashMap.class);
                        var eventScripts = requestJson.get("eventScripts");
                        if (eventScripts == null || "[]".equals(eventScripts)) {
                            //远程调用服务
                            val form_model = DbHelper.get(ContextUtils.getBean(DataSource.class, false), (c) -> {
                                return new paas_form_model_dal().get(c, formInfo.formKey);
                            });
                            eventScripts = form_model.form_design_event;
                        }
                        eventScripts = (eventScripts ==null? "[]":eventScripts);
                        val es = new EventScripts((String)eventScripts);
                        val beforeScript = es.filter(formInfo.formAction, "before");
                        if (!StringUtils.isEmpty(beforeScript)) {
                            try {
                                val requestJson2 = DynamicScript.run(formInfoStr, beforeScript, requestJson);
                                requestWrapper.setBody(jsonSerializer.serialize(requestJson2).getBytes(StandardCharsets.UTF_8));
                            } catch (Exception e) {
                                LogUtils.error(this.getClass(), "", "动态事件流前置事件出错:" + formInfoStr, e);
                            }
                        }
                        //原始请求
                        chain.doFilter(requestWrapper, response);
                        val afterScript = es.filter(formInfo.formAction, "after");
                        if (!StringUtils.isEmpty(afterScript)) {
                            try {
                                DynamicScript.run(formInfoStr, afterScript, requestJson);
                            } catch (Exception e) {
                                LogUtils.error(this.getClass(), "", "动态事件流后置事件出错:" + formInfoStr, e);
                            }
                        }
                        return;
                    }

                } catch (Exception e) {
                    //将错误信息绑定上下文，由前后端交互协议中的debug信息进行输出。
                    LogUtils.error(FormEventFilter.class, ExceptionUtils.getDetailMessage(e));
                    throw e;
                }
            }
        }
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
    }

    @Override
    public void init(FilterConfig filterConfig) {
    }

    @AllArgsConstructor
    private static class formInfo {
        public String formKey;
        public String formAction;
    }
}

